package novoseltsev.sasha.client;


import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DragEndEvent;
import com.google.gwt.event.dom.client.DragEndHandler;
import com.google.gwt.event.dom.client.DragLeaveEvent;
import com.google.gwt.event.dom.client.DragLeaveHandler;
import com.google.gwt.event.dom.client.DragOverEvent;
import com.google.gwt.event.dom.client.DragOverHandler;
import com.google.gwt.event.dom.client.DragStartEvent;
import com.google.gwt.event.dom.client.DragStartHandler;
import com.google.gwt.event.dom.client.DropEvent;
import com.google.gwt.event.dom.client.DropHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.layout.client.Layout.Alignment;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import java.lang.Class;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.rpc.AsyncCallback;



public class DrawJavaBean implements EntryPoint {
	
	DataServiceAsync dataServiceProxy = null;
	Tree tree = new Tree();
	Tree xmlTree = new Tree();
	ListBox availableClasses = new ListBox();
	ListBox availableXmls = new ListBox();
	Label xmlToClass = new Label();
	Label rulesLabel = new Label();
	
	public void onModuleLoad() {
		InitializeScreenLayout();
	}
	
	void InitializeScreenLayout() {
		DockLayoutPanel mainPanel = new DockLayoutPanel(Unit.PX);
		SimplePanel wrapper1 = new SimplePanel();
		SimplePanel wrapper2 = new SimplePanel();
		VerticalPanel wrapper3 = new VerticalPanel();
 		
		VerticalPanel leftPanel = CreateAnotherLeftPanel();
		VerticalPanel rightPanel = new VerticalPanel();
		
		HTML header = new HTML("JavaBeen to XML mapping");
		HTML errors = new HTML();
		
		availableClasses = CreateListBoxForAvailableClasses();
		
		header.getElement().setAttribute("style", "text-align: center; font-size: larger;");
		wrapper1.getElement().setAttribute("style", "background-color: #F2EBEE;" + "padding: 5px; border: 2px solid black; text-align: center; border-radius: 8px;");
		wrapper2.getElement().setAttribute("style", "background-color: #F2EBEE;" + "padding: 5px; border: 2px solid black; text-align: center; border-radius: 8px;");
		rightPanel.getElement().setAttribute("style", "margin: 0px auto;");
		leftPanel.getElement().setAttribute("style", "margin: 0px auto;");
		
		wrapper1.add(leftPanel);
		
		rightPanel.add(availableClasses);
		rightPanel.add(tree);
		wrapper2.add(rightPanel);
		
		wrapper3.getElement().setAttribute("style", "margin: 0px auto;");
		wrapper3.add(xmlToClass);
		wrapper3.add(rulesLabel);		
		
		mainPanel.addNorth(header, 55);
		mainPanel.addWest(wrapper1, 450);
		mainPanel.addEast(wrapper2, 450);
		mainPanel.add(wrapper3);
		RootLayoutPanel.get().add(mainPanel);
	}	

	private VerticalPanel CreateLeftPanel() {
		VerticalPanel panel = new VerticalPanel();
		Label label = new Label();
		SimplePanel dragPanel = new SimplePanel();
		
		String style = "background-color: white; ";
		style += "border: 2px solid black; ";
		style += "border-radius: 8px; ";
		style += "width: 200px; ";
		style += "height: 300px; ";
		dragPanel.getElement().setAttribute("style", style);
		
		MakePanelAppropriateForDropEvent(dragPanel, label);
		
		style = "width: 200px; height: 60px;";
		label.getElement().setAttribute("style", style);
		
		panel.getElement().setAttribute("style", "margin: 0px auto;");
		
		panel.add(label);
		panel.add(dragPanel);
		return panel;
	}
	
	private void MakePanelAppropriateForDropEvent(final SimplePanel panel, final Label label) {
		panel.addDomHandler(new DragOverHandler() {

			@Override
			public void onDragOver(DragOverEvent event) {
				String style = ((SimplePanel) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("background-color: white;", "background-color: yellow;");
				((SimplePanel) event.getSource()).getElement().setAttribute("style", style);
			}
			
		}, DragOverEvent.getType());
		
		panel.addDomHandler(new DropHandler() {

			@Override
			public void onDrop(DropEvent event) {
				event.preventDefault();
				String[] data = event.getData("text").split(" ");
				String className = data[0];
				String fieldName = data[1];
				label.setText(fieldName + " field of " + className + " class was Drag'n'Dropped");
				String style = ((SimplePanel) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("background-color: yellow;", "background-color: white;");
				((SimplePanel) event.getSource()).getElement().setAttribute("style", style);
			}
			
		}, DropEvent.getType());
		
		panel.addDomHandler(new DragLeaveHandler() {

			public void onDragLeave(DragLeaveEvent event) {
				String style = ((SimplePanel) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("background-color: yellow;", "background-color: white;");
				((SimplePanel) event.getSource()).getElement().setAttribute("style", style);
			}
			
		}, DragLeaveEvent.getType());
		
	}
	
	private ListBox CreateListBoxForAvailableClasses() {
		final ListBox lb = new ListBox();
		if (dataServiceProxy == null) {
			dataServiceProxy = GWT.create(DataService.class);
		}
		
		AsyncCallback<String[]> callback = new AsyncCallback<String[]>() {
			public void onFailure(Throwable caught) {
				HTML errors = (HTML) RootLayoutPanel.get().getWidget(4);
				errors.setText(caught.getMessage());
			}
			
			public void onSuccess(String[] result) {
				lb.clear();
				for (int i = 0; i<result.length; ++i){
		        	lb.addItem(result[i]);
		        }
			}
		};
		
		lb.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				String selectedItem = lb.getValue(lb.getSelectedIndex());
				InitializeJavaBeanTree(selectedItem);
			}
			
		});
		dataServiceProxy.getAvailableJavaBeanClasses(callback);
		
		return lb;
	}

	void InitializeJavaBeanTree(String className) {
		if (dataServiceProxy == null) {
			dataServiceProxy = GWT.create(DataService.class);
		}
		// Set up the callback object.
	    AsyncCallback<String[]> callback = new AsyncCallback<String[]>() {
	      public void onFailure(Throwable caught) {
	        tree.addItem(caught.getMessage());
	      }

	      public void onSuccess(String[] result) {
	    	tree.clear();
	        for (int i = 0; i<result.length; ++i){
	        	tree.addItem(CreateTreeElem(result[i]));
	        }
	      }
	    };
	    dataServiceProxy.getMethodNames(className, callback);
	}
	
	private HTML CreateTreeElem(String field) {
		HTML element = new HTML(field);
		String style = "border: 2px solid red; text-align: center; border-radius: 8px;";
		element.getElement().setAttribute("style", style);
		MakeElemDraggable(element);
		return element;
	}
	
	private void MakeElemDraggable(final HTML element) {
		element.getElement().setDraggable(Element.DRAGGABLE_TRUE);
		element.addDragStartHandler(new DragStartHandler() {
			public void onDragStart(DragStartEvent event) {
				String classSelected = availableClasses.getValue(availableClasses.getSelectedIndex());
				event.setData("text",  classSelected + " " + element.getText());
				
				event.getDataTransfer().setDragImage(element.getElement(), 
						element.getOffsetWidth(), 
						element.getOffsetHeight());
				
				String style = ((HTML) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("red", "green");
				style = style.replaceAll("border: 2px", "border: 3px");
				((HTML) event.getSource()).getElement().setAttribute("style", style);
			}
		});
		
		element.addDragEndHandler(new DragEndHandler() {

			@Override
			public void onDragEnd(DragEndEvent event) {
				String style = ((HTML) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("green", "red");
				style = style.replaceAll("border: 3px", "border: 2px");
				((HTML) event.getSource()).getElement().setAttribute("style", style);
			}
			
		});
		
	}
	
	private VerticalPanel CreateAnotherLeftPanel() {
		VerticalPanel panel = new VerticalPanel();
		
		CreateAvailableXmlsListBox(availableXmls);
		panel.add(availableXmls);
		panel.add(xmlTree);
		return panel;
	}
	
	private void CreateAvailableXmlsListBox(final ListBox listBox) {
		if (dataServiceProxy == null) {
			dataServiceProxy = GWT.create(DataService.class);
		}
		AsyncCallback<String[]> callback = new AsyncCallback<String[]>() {
		      public void onFailure(Throwable caught) {
		        listBox.addItem(caught.getMessage());
		      }

		      public void onSuccess(String[] result) {
		    	listBox.clear();
		        for (int i = 0; i<result.length; ++i){
		        	listBox.addItem(result[i]);
		        }
		      }
		    };
	    dataServiceProxy.getAvailableXmls(callback);
	    
	    listBox.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				ListBox box = ( (ListBox) (event.getSource()));
				String selectedItem = box.getValue(box.getSelectedIndex());
				CreateXmlTree(selectedItem, xmlTree);
			}
		});
	}
	
	private void CreateXmlTree(String fileName, final Tree xmlTree) {
		if (dataServiceProxy == null) {
			dataServiceProxy = GWT.create(DataService.class);
		}
		AsyncCallback<String[]> callback = new AsyncCallback<String[]>() {
		      public void onFailure(Throwable caught) {
		        xmlTree.addItem(caught.getMessage());
		      }

		      public void onSuccess(String[] result) {
		    	  xmlTree.clear();
		        for (int i = 0; i<result.length; ++i){
		        	xmlTree.addItem(CreateXmlTreeElem(result[i]));
		        }
		      }
		    };
	    dataServiceProxy.getAvailableNodes(fileName, callback);
	}
	
	private HTML CreateXmlTreeElem(String content) {
		HTML element = new HTML(content);
		String style = "border: 2px solid red; text-align: center; border-radius: 8px; background-color: white;";
		element.getElement().setAttribute("style", style);
		MakeElemAppropriateForDrop(element, rulesLabel);
		return element;
	}
	
	private void MakeElemAppropriateForDrop(final HTML elem, final Label label) {
		elem.addDomHandler(new DragOverHandler() {

			@Override
			public void onDragOver(DragOverEvent event) {
				String style = ((HTML) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("background-color: white;", "background-color: yellow;");
				((HTML) event.getSource()).getElement().setAttribute("style", style);
			}
			
		}, DragOverEvent.getType());
		
		elem.addDomHandler(new DropHandler() {

			@Override
			public void onDrop(DropEvent event) {
				event.preventDefault();
				String[] data = event.getData("text").split(" ");
				String className = data[0];
				String fieldName = data[1];
				
				String[] xmlData = elem.getText().split(" ");
				String xmlName = availableXmls.getValue(availableXmls.getSelectedIndex());
				String xmlNodeName = xmlData[0];
				String xmlNodeValue = xmlData[1];
				
				String text = xmlName + " => " + className;
				xmlToClass.setText(text);
				text = xmlNodeName + " " + xmlNodeValue + " => " + fieldName;
				label.setText(text);
				DOM.setStyleAttribute(label.getElement(), "whiteSpace", "pre"); 
				String style = ((HTML) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("background-color: yellow;", "background-color: white;");
				((HTML) event.getSource()).getElement().setAttribute("style", style);
			}
			
		}, DropEvent.getType());
		
		elem.addDomHandler(new DragLeaveHandler() {

			public void onDragLeave(DragLeaveEvent event) {
				String style = ((HTML) event.getSource()).getElement().getAttribute("style");
				style = style.replaceAll("background-color: yellow;", "background-color: white;");
				((HTML) event.getSource()).getElement().setAttribute("style", style);
			}
			
		}, DragLeaveEvent.getType());
	}
	
}
